package es.upm.gib.mappingAPI2;

import java.io.Serializable;

/**
 * Class CoordinatesBound represents coordinates bounds of two different paths
 * There are four coordinates:
 * - Number of the first path to represent
 * - Number of the class of the first path to represent
 * - Number of the second path to represent
 * - Number of the class of the second path to represent
 * 
 */
public class CoordinatesBound implements Serializable , Comparable<CoordinatesBound>{

    //=======================================================================
    //ATTRIBUTES
    //=======================================================================

    /**
     * First coordinate of the bound
     */
    private Coordinate firstCoordinate;

    /**
     * Second coordinate of the bound
     */
    private Coordinate secondCoordinate;

    //=======================================================================
    // CONSTRUCTORS
    //=======================================================================

    /**
     * Constructor
     *
     * @param firstPath value of the first coordinate path
     * @param firstClass position of the first coordinate class
     * @param secondPath value of the second coordinate path
     * @param secondClass position of the second coordinate class
     */
    public CoordinatesBound(int firstPath, int firstClass, int secondPath, int secondClass) {
        this.firstCoordinate = new Coordinate(firstPath, firstClass);
        this.secondCoordinate = new Coordinate(secondPath, secondClass);
    }

    //=======================================================================
    // PUBLIC METHODS
    //=======================================================================

    /**
     * returns  the position of the class in the first view
     *
     * @return the position of the class in the first view
     */
    public int getFirstClass() {
        return firstCoordinate.getClass_();
    }

    /**
     * returns the position of the class in the second view
     *
     * @return the position of the class in the second view
     */
    public int getSecondClass() {
        return secondCoordinate.getClass_();
    }

    /**
     * returns the number of the path in the first view
     *
     * @return the number of the path in the first view
     */
    public int getFirstPath() {
        return firstCoordinate.getPath();
    }

    /**
     * returns the number of the path in the second view
     *
     * @return the number of the path in the second view
     */
    public int getSecondPath() {
        return secondCoordinate.getPath();
    }

    void normalize() {
        if (compareElements(firstCoordinate.getPath(), firstCoordinate.getClass_(), secondCoordinate.getPath(), secondCoordinate.getClass_()) > 0) {
            switchElements();
        }
    }

    /**
     * This class switch both coordinates
     */
    private void switchElements() {
        int tempFirstPath = firstCoordinate.getPath();
        int tempFirstClass = firstCoordinate.getClass_();
        firstCoordinate = new Coordinate(secondCoordinate.getPath(), secondCoordinate.getClass_());
        secondCoordinate = new Coordinate(tempFirstPath, tempFirstClass);
    }

    /**
     * This method compares two CoordinatesBound objects
     * @param otherInternalBound object to compare
     * @return
     * - 0 if the coordinates of the objects are coincident
     * - 1
     * - -1
     */
    public int compareTo(CoordinatesBound otherInternalBound) {
        /*if (!(otherInternalBound instanceof CoordinatesBound)) {
            throw new ClassCastException("Invalid object");
        } */
        CoordinatesBound otherIB = otherInternalBound;
        if (compareElements(firstCoordinate.getPath(), firstCoordinate.getClass_(), otherIB.firstCoordinate.getPath(), otherIB.firstCoordinate.getClass_()) < 0) {
            return -1;
        } else if (compareElements(firstCoordinate.getPath(), firstCoordinate.getClass_(), otherIB.firstCoordinate.getPath(), otherIB.firstCoordinate.getClass_()) > 0) {
            return 1;
        } else if (compareElements(secondCoordinate.getPath(), secondCoordinate.getClass_(), otherIB.secondCoordinate.getPath(), otherIB.secondCoordinate.getClass_()) < 0) {
            return -1;
        } else if (compareElements(secondCoordinate.getPath(), secondCoordinate.getClass_(), otherIB.secondCoordinate.getPath(), otherIB.secondCoordinate.getClass_()) > 0) {
            return 1;
        } else {
            return 0;
        }
    }

    /**
     * This method determines if the input parameters are coincident
     *
     * @param pathA value of the first path to compare
     * @param classA value of the first class to compare
     * @param pathB value of the second path to compare
     * @param classB value of the second class to compare
     * @return
     *  - 0 if pathA = pathB and classA = classB
     *  - 1 if pathA > pathB or pathA = pathB and classA > classB
     *  - -1 otherwise
     */
    private int compareElements(int pathA, int classA, int pathB, int classB) {
        if (pathA < pathB) {
            return -1;
        } else if (pathA > pathB) {
            return 1;
        } else if (classA < classB) {
            return -1;
        } else if (classA > classB) {
            return 1;
        } else {
            return 0;
        }
    }

    @Override
    public String toString() {
        return "{" + firstCoordinate + " = " + secondCoordinate + "}";
    }

    //@Override
    /*public int compareTo(CoordinatesBound o) {
        return 0;  //To change body of implemented methods use File | Settings | File Templates.
    } */

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        CoordinatesBound bound = (CoordinatesBound) o;

        if (!firstCoordinate.equals(bound.firstCoordinate)) return false;
        if (!secondCoordinate.equals(bound.secondCoordinate)) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = firstCoordinate.hashCode();
        result = 31 * result + secondCoordinate.hashCode();
        return result;
    }
}
